<?php declare(strict_types=1);

namespace Zyucv7\Components\Http;

use Zyucv7\Components\Http\HttpException;
use Zyucv7\Components\Http\Client\Curl;

/**
 * HTTP客户端类
 * 用于向第三方API发送HTTP请求，支持GET和POST方法
 */
class Client
{
    /** 
     * API 基础URL
     * 
     * @var string
     */
    private $baseUrl;

    /** 
     * 请求对象
     * 
     * @var Curl
     */
    private Curl $curl;

    /** 
     * 响应数据
     * 
     * @var array
     */
    private array $respData = [];

    /** 
     * 配置选项
     * 
     * @var array
     */
    private array $options = [
        'timeout' => 60,
        'verify_ssl' => true,
    ];

    /**
     * HttpClient构造函数
     * 
     * @param string $baseUrl API基础URL
     * @param array $options 配置选项，如 ['timeout' => 60, 'verify_ssl' => false]
     */
    public function __construct(string $baseUrl, array $options = [])
    {
        $this->baseUrl = rtrim($baseUrl, '/');
        $this->options['verify_ssl'] = !v7_is_local();
        $this->options = array_merge($this->options, $options);
    }

    /**
     * 设置是否验证SSL证书
     * 用于在本地开发环境中绕过SSL验证
     * 
     * @param bool $verifySsl 是否验证SSL证书
     * @return void
     */
    public function setVerifySsl(bool $verifySsl)
    {
        $this->options['verify_ssl'] = $verifySsl;
    }

    /**
     * 添加请求头
     * 用于添加自定义请求头信息
     * 
     * @param string $key 请求头字段名
     * @param string $value 请求头字段值
     * @return self
     */
    public function addHeader(string $key, string $value): self
    {
        if(!isset($this->options['headers'])) {
            $this->options['headers'] = [];
        }
        $this->options['headers'][$key] = $value;
        return $this;
    }

    /**
     * 构建请求URL
     * 将基础URL与路径和参数组合成完整URL
     * 
     * @param string $url 请求路径
     * @param array $params URL参数
     * @return string 完整的请求URL
     */
    public function buildUrl(string $url, array $params = []) {
        if (!empty($params)) {
            $url .= (stripos($url, '?') !== false ? '&' : '?') . http_build_query($params);
        }
        return $this->baseUrl . $url;
    }

    /**
     * 检查请求错误
     * 验证请求是否成功，如果失败则抛出相应异常
     * 
     * @return void
     * @throws HttpException
     */
    private function checkError() {
        if ($error = $this->curl->getError()) {
            throw HttpException::curlErr($error);
        }

        $httpCode = $this->curl->getHttpCode();
        if ($httpCode >= 400) {
            throw HttpException::httpErr('HTTP Code '.$httpCode.V7_EOL.$this->curl->getRaw());
        }

        $data = $this->curl->getData();
        if ($data === false) {
            throw HttpException::jsonErr($httpCode.V7_EOL.$this->curl->getRaw());
        };

        $this->respData = $data;
    }

    /**
     * 发起HTTP GET 请求
     * 向指定URL发送GET请求并处理响应
     * 
     * @param string $url 请求URL路径
     * @return self 返回当前实例以支持链式调用
     * @throws HttpException
     */
    public function get(string $url) {
        // 构建请求URL
        $url = $this->buildUrl($url);
        $this->curl = new Curl($url, $this->options);
        $this->curl->sendGet();
        $this->checkError();
        return $this;
    }

    /**
     * 发起HTTP POST 请求
     * 向指定URL发送POST请求并处理响应
     * 
     * @param string $url 请求URL路径
     * @param mixed $body POST数据
     * @return self 返回当前实例以支持链式调用
     * @throws HttpException
     */
    public function post(string $url, $body) {
        // 构建请求URL
        $url = $this->buildUrl($url);
        $this->curl = new Curl($url, $this->options);
        $this->curl->sendPost($body);
        $this->checkError();
        return $this;
    }

    /**
     * 获取响应数据
     * 返回解析后的响应数据
     * 
     * @return array 响应数据
     */
    public function getData() {
        return $this->respData;
    }
}
?>